package com.n.passwordbook.MainWindow;

import com.n.passwordbook.AboutWindow.AboutWindow;
import com.n.passwordbook.Launcher;
import com.n.passwordbook.PasswordBook.PasswordBook;
import com.n.passwordbook.PasswordBook.PasswordStruct;
import com.n.passwordbook.SettingsWindow.SettingsWindow;
import com.n.passwordbook.Utils.*;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import org.apache.commons.lang3.StringUtils;

import javax.swing.ImageIcon;
import javax.swing.event.MouseInputAdapter;
import java.awt.AWTException;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.io.File;
import java.net.URL;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;

public class MainWindow implements Initializable
{
    @FXML
    public TableView<PasswordStruct> tv_passwords;
    @FXML
    public ImageView iv_minimize;
    @FXML
    public ImageView iv_openSettingsWindow;
    @FXML
    public Text txt_showLastTime;
    @FXML
    public Text txt_hello;
    @FXML
    public TextField tb_search;
    @FXML
    public TextField tb_name;
    @FXML
    public TextField tb_password;
    @FXML
    public TextField tb_remark;
    @FXML
    public Canvas cv_particle;

    private Clipboard passwordClipboard;
    private ContextMenu cm_copyPassword;

    private static final String SHOW_LAST_TIME_DESC = "上次保存时间：";
    private static final String SAY_HELLO_DESC = "你好，";
    private ParticleSystem particleBackground;

    private boolean isShowed;

    public void buttonOnMouseEnteredAnimation(MouseEvent e)
    {
        PageHelper.mouseInButtonAnimation(e);
    }

    public void buttonOnMouseExitedAnimation(MouseEvent e)
    {
        PageHelper.mouseExitedButtonAnimation(e);
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle)
    {
        //初始化托盘图标
        if (!SystemTray.isSupported())
        {
            iv_minimize.setOpacity(0);
        }
        else
        {
            TrayIcon trayIcon = new TrayIcon(new ImageIcon(Objects.requireNonNull(Launcher.class.getResource("resource/icon.png"))).getImage());
            trayIcon.setImageAutoSize(true);
            trayIcon.setToolTip("PasswordBook");
            isShowed = true;
            WindowHelper.MainStage.setOnHidden(e -> isShowed = false);
            WindowHelper.MainStage.setOnShown(e -> isShowed = true);
            trayIcon.addMouseListener(new MouseInputAdapter()
            {
                @Override
                public void mouseClicked(java.awt.event.MouseEvent e)
                {
                    Platform.runLater(() -> {
                        if (isShowed)
                        {
                            WindowHelper.MainStage.hide();
                        }
                        else
                        {
                            WindowHelper.MainStage.setIconified(false);
                            if (!WindowHelper.MainStage.isShowing())
                            {
                                WindowHelper.MainStage.show();
                            }
                            WindowHelper.MainStage.toFront();
                        }
                    });
                }
            });
            try
            {
                SystemTray.getSystemTray().add(trayIcon);
            }
            catch (AWTException e)
            {
                e.printStackTrace();
            }
        }
        //初始化剪贴板
        Platform.runLater(() -> passwordClipboard = Clipboard.getSystemClipboard());
        //初始化右键菜单
        cm_copyPassword = new ContextMenu();
        var copyItem = new MenuItem("复制密码明文");
        copyItem.setOnAction(e -> {
            var passwordContent = new ClipboardContent();
            var password = tv_passwords.getSelectionModel().getSelectedItem().getPassword(PasswordBook.PBKey);
            passwordContent.putString(password);
            passwordClipboard.setContent(passwordContent);
        });
        cm_copyPassword.getItems().add(copyItem);
    }


    public static void initializeControllerManually(Object mainWindow)
    {
        MainWindow window = (MainWindow) mainWindow;
        //读取密码本文件
        PasswordBook.readPasswordBook();
        //设置文本初始值
        window.showUserName(true);
        window.txt_showLastTime.setText(SHOW_LAST_TIME_DESC + PasswordBook.getLastSaveTime());
        //设置TableView的数据绑定
        window.tv_passwords.setItems(PasswordBook.Passwords);
        PasswordBook.resetTableView(window.tv_passwords);
        OperationManager.reset(PasswordBook.Passwords, window.tv_passwords);
        window.tv_passwords.getSelectionModel().select(0);
        //设置TableView的右键菜单
        window.tv_passwords.setContextMenu(window.cm_copyPassword);
        //设置事件
        window.tb_search.textProperty().addListener(((observableValue, oldValue, newValue) -> window.callSearcher()));
        //初始化背景
        window.cv_particle.setOpacity(Settings.getAnimatedBackgroundOpacity());
        window.particleBackground = new ParticleSystem(window.cv_particle, 175, Color.BLACK, 3);
        if (Settings.getUseAnimatedBackground())
        {
            window.particleBackground.start();
        }
        //设置TableView编辑提交后的动作
        CustomTextFieldTableCell.functionOnCommit = b -> {
            OperationManager.getInstance().Do(PasswordBook.Passwords);
            window.showUserName(b);
        };
        addAccelerators(mainWindow);
    }

    public static void addAccelerators(Object mainWindow)
    {
        //设置快捷键
        WindowHelper.MainScene.getAccelerators().put(new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN),
                () -> ((MainWindow) mainWindow).ivOnMouseClickSave(null));//ctrl + s 保存
        WindowHelper.MainScene.getAccelerators().put(new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN),
                () -> ((MainWindow) mainWindow).ivOnMouseClickSaveAs(null));//ctrl + shift + s 另存为
        WindowHelper.MainScene.getAccelerators().put(new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN, KeyCombination.ALT_DOWN),
                SettingsWindow::show);//ctrl + alt + s 打开设置
        WindowHelper.MainScene.getAccelerators().put(new KeyCodeCombination(KeyCode.Z, KeyCombination.CONTROL_DOWN),
                () -> ((MainWindow) mainWindow).ivOnMouseClickUndo(null));//ctrl + Z 撤销
        WindowHelper.MainScene.getAccelerators().put(new KeyCodeCombination(KeyCode.Y, KeyCombination.CONTROL_DOWN),
                () -> ((MainWindow) mainWindow).ivOnMouseClickRedo(null));//ctrl + Y 重做
        WindowHelper.MainScene.getAccelerators().put(new KeyCodeCombination(KeyCode.BACK_SPACE),
                () -> ((MainWindow) mainWindow).ivOnMouseClickDelete(null));//退格 删除单条密码
        WindowHelper.MainScene.getAccelerators().put(new KeyCodeCombination(KeyCode.F, KeyCombination.CONTROL_DOWN),
                () -> ((MainWindow) mainWindow).tb_search.requestFocus());//ctrl + F 查找
        //鼠标点击窗口时强制移除TextFiled（等控件）的焦点，方便触发快捷键
        WindowHelper.MainScene.setOnMouseClicked(e -> WindowHelper.MainScene.getRoot().getChildrenUnmodifiable().get(0).requestFocus());
        //添加窗口鼠标移动时事件
        WindowHelper.MainScene.setOnMouseMoved(e -> {
            ((MainWindow) mainWindow).particleBackground.mouseX = e.getX();
            ((MainWindow) mainWindow).particleBackground.mouseY = e.getY();
        });
    }


    public void buAddPasswordOnAction(ActionEvent e)
    {
        AddPasswordToTableView();
    }

    private void AddPasswordToTableView()
    {
        if (StringUtils.isNotEmpty(tb_name.getText()) && StringUtils.isNotEmpty(tb_password.getText()))//帐号和密码不为空
        {
            tv_passwords.getItems().add(new PasswordStruct(tb_name.getText(), tb_password.getText(), tb_remark.getText(), 0, PasswordBook.PBKey));
            showUserName(OperationManager.getInstance().Do(PasswordBook.Passwords));
            tv_passwords.getSelectionModel().select(tv_passwords.getItems().size() - 1);
            tv_passwords.scrollTo(tv_passwords.getItems().size() - 1);

            tb_name.setText("");
            tb_password.setText("");
            tb_remark.setText("");

            tb_name.requestFocus();
        }
    }

    public void tbAddPasswordOnAction(ActionEvent e)
    {
        AddPasswordToTableView();
    }

    public void ivOnMouseEnteredAnimation(MouseEvent e)
    {
        PageHelper.imageViewOnMouseIn(e);
    }

    public void ivOnMouseExitedAnimation(MouseEvent e)
    {
        PageHelper.imageViewOnMouseOut(e);
    }

    public void ivOnMouseClickQuit(MouseEvent e)
    {
        System.exit(0);
    }

    public void ivOnMouseClickSave(MouseEvent e)
    {
        if (e != null)
        {
            PageHelper.imageViewOnMouseClick(e);
        }
        txt_showLastTime.setText(SHOW_LAST_TIME_DESC + PasswordBook.savePasswordBook());
        showUserName(true);
        OperationManager.getInstance().saveSuccessfully();
    }

    public void ivOnMouseClickSaveAs(MouseEvent e)
    {
        File path = Helper.selectPasswordBookFileAs("将文件副本储存到");
        if (path != null)
        {
            String extensionName = StringUtils.substringAfterLast(path.getName(), '.');
            String saveTime = null;
            if (extensionName.equals("pb"))
            {
                saveTime = PasswordBook.savePasswordBook(path);
            }
            else if (extensionName.equals("csv"))
            {
                saveTime = PasswordBook.exportToCSV(path);
            }
            if (saveTime != null)
            {
                final String oldStr = txt_showLastTime.getText();
                //保存成功后更新显示内容
                txt_showLastTime.setText("文件另存为成功，保存时间：" + saveTime);
                showUserName(true);
                OperationManager.getInstance().saveSuccessfully();//通知OperatorManager保存成功
                final String changedStr = txt_showLastTime.getText();
                new Timer().schedule(new TimerTask()
                {
                    @Override
                    public void run()
                    {
                        if (StringUtils.equals(txt_showLastTime.getText(), changedStr))//显示完保存成功消息后恢复提示信息
                        {
                            txt_showLastTime.setText(oldStr);
                        }
                    }
                }, 5000);
            }
        }
    }

    public void ivOnMouseClickDelete(MouseEvent mouseEvent)
    {
        int selectedIndex;
        if ((selectedIndex = tv_passwords.getSelectionModel().getSelectedIndex()) != -1 && selectedIndex >= 0 && selectedIndex < PasswordBook.Passwords.size())
        {
            PasswordBook.Passwords.remove(selectedIndex);
            showUserName(OperationManager.getInstance().Do(PasswordBook.Passwords));
        }
    }

    public void hlAboutOnActionShowAbout(ActionEvent actionEvent)
    {
        AboutWindow.show();
    }

    public void lightenOnMouseIn(MouseEvent mouseEvent)
    {
        PageHelper.lightenOnMouseIn(mouseEvent);
    }

    public void lightenOnMouseOut(MouseEvent mouseEvent)
    {
        PageHelper.lightenOnMouseOut(mouseEvent);
    }

    public void ivOpenSettingsWindowOnMouseClicked(MouseEvent mouseEvent)
    {
        SettingsWindow.show();
    }

    public void ivOnMouseClickUndo(MouseEvent mouseEvent)
    {
        showUserName(OperationManager.getInstance().undo());
    }

    public void ivOnMouseClickRedo(MouseEvent mouseEvent)
    {
        showUserName(OperationManager.getInstance().redo());
    }

    public void tbMoveFocusToLeftNode(KeyEvent keyEvent)
    {
        var tb = (TextField) keyEvent.getSource();
        var cursorIndex = tb.getSelection().getStart();
        if (cursorIndex == 0)
        {
            if (keyEvent.getCode() == KeyCode.LEFT)
            {
                tb_password.requestFocus();
            }
        }
    }

    public void tbMoveFocusTo(KeyEvent keyEvent)
    {
        var tb = (TextField) keyEvent.getSource();
        var cursorIndex = tb.getSelection().getStart();
        if (cursorIndex == 0 || cursorIndex >= tb.getText().length())
        {
            switch (keyEvent.getCode())
            {
                case LEFT -> tb_name.requestFocus();
                case RIGHT -> tb_remark.requestFocus();
                case DOWN -> tb_password.setText(PasswordGenerator.generatePassword());
            }
        }
    }

    public void tbSetFocusedToRightNode(KeyEvent keyEvent)
    {
        var tb = (TextField) keyEvent.getSource();
        var cursorIndex = tb.getSelection().getStart();
        if (cursorIndex >= tb.getText().length())
        {
            if (keyEvent.getCode() == KeyCode.RIGHT)
            {
                tb_password.requestFocus();
            }
        }
    }

    public void ivOnMouseClickedMinimize(MouseEvent mouseEvent)
    {
        WindowHelper.MainStage.hide();
    }

    public void ivOnCleanClipBoard(MouseEvent mouseEvent)
    {
        var emptyContent = new ClipboardContent();
        emptyContent.putString(" ");
        passwordClipboard.setContent(emptyContent);
    }

    public ParticleSystem getParticleBackground()
    {
        return particleBackground;
    }

    public Canvas getParticleCanvas()
    {
        return cv_particle;
    }

    private void callSearcher()
    {
        if (StringUtils.isNotEmpty(tb_search.getText()))
        {
            Searcher.search(tb_search.getText());
            tv_passwords.getSelectionModel().select(0);
        }
        else
        {
            Searcher.reset();
        }
    }

    private void showUserName(boolean isPasswordBookSame)
    {
        if (isPasswordBookSame)
        {
            txt_hello.setText(SAY_HELLO_DESC + PasswordBook.UserName);
        }
        else
        {
            txt_hello.setText(SAY_HELLO_DESC + PasswordBook.UserName + '*');
        }
    }

    public void buUpPassword(ActionEvent actionEvent)
    {
        int index = tv_passwords.getSelectionModel().getSelectedIndex();
        if (index > 0)
        {
            var followingPassword = PasswordBook.Passwords.get(index);
            PasswordBook.Passwords.set(index, PasswordBook.Passwords.get(index - 1));
            PasswordBook.Passwords.set(index - 1, followingPassword);
            tv_passwords.getSelectionModel().select(index - 1);
            showUserName(OperationManager.getInstance().Do(PasswordBook.Passwords));
        }
    }

    public void buDownPassword(ActionEvent actionEvent)
    {
        int index = tv_passwords.getSelectionModel().getSelectedIndex();
        if (index < PasswordBook.Passwords.size() - 1)
        {
            var upperPassword = PasswordBook.Passwords.get(index);
            PasswordBook.Passwords.set(index, PasswordBook.Passwords.get(index + 1));
            PasswordBook.Passwords.set(index + 1, upperPassword);
            tv_passwords.getSelectionModel().select(index + 1);
            showUserName(OperationManager.getInstance().Do(PasswordBook.Passwords));
        }
    }
}
